package com.mytomcat;

import com.mytomcat.annotation.WebInitParam;
import com.mytomcat.annotation.WebServlet;
import com.mytomcat.config.ServletConfig;
import com.mytomcat.config.ServletMapping;
import com.mytomcat.servlet.MyHttpServlet;
import com.mytomcat.servlet.MyHttpServletRequest;
import com.mytomcat.servlet.MyHttpServletResponse;
import com.mytomcat.servlet.impl._404Servlet;
import com.sun.corba.se.spi.orbutil.threadpool.ThreadPool;
import com.util.log.Logger;

import java.io.File;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Tomcat总配置
 */
public class MyTomcat {
    private static Logger log = Logger.getLogger(MyTomcat.class);

    private int port = 8080;

    // 每个Servlet的配置信息
    private Map<String, ServletMapping> urlServletMap = new HashMap<>();
    // 每个Servlet实例 单例模式
    private Map<String, MyHttpServlet> servletMap = new HashMap<>();

    public MyTomcat() {
    }

    public MyTomcat(int port) {
        this.port = port;
    }

    public void start() throws Exception {
        // 初始化servlet映射配置
        initServletMapping();

        try (ServerSocket serverSocket = new ServerSocket(port)) {
            // 使用线程池处理
            Executor threadPool = new ThreadPoolExecutor(10, 100,
                    0L, TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>());

            log.info(" MyTomcat服务已开启 端口号: " + port);

            for (; ; ) {
                Socket socket = serverSocket.accept();
                // 每个请求都开启新线程
                threadPool.execute(() -> {
                    try {
                        MyHttpServletRequest request = new MyHttpServletRequest(socket);
                        MyHttpServletResponse response = new MyHttpServletResponse(socket);
                        // 调用相关servlet
                        dispatch(request, response);
                        if (!socket.isClosed())
                            socket.close(); // 断开连接
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 初始化servlet映射配置
    private void initServletMapping() throws Exception {
        String rootPackage = this.getClass().getTypeName().split("\\.")[0]; // 直接扫描工程下所有类
        doScannerWebServlet(rootPackage);
        log.info("servlet映射配置加载成功：");
        urlServletMap.forEach((key, value) -> {
            log.info("[" + value.getUrlPattern() + "] servletClass" + value.getClassName());
        });
        log.info("servlet实例: ");
        servletMap.forEach((key, value) -> {
            log.info("[" + key + "] " + value);
        });
    }

    /**
     * 扫描类 找注解@WebServlet进行Servlet的加载与配置
     *
     * @param packageName
     */
    private void doScannerWebServlet(String packageName) throws Exception {
        // 当前类工程的class路径 如果不加“/” ，获取当前类的绝对路径
        String projectClassPath = this.getClass().getClassLoader().getResource("").toURI().getPath();
        File dir = new File(projectClassPath.substring(1), packageName.replaceAll("\\.", "/"));
        File[] files = dir.listFiles();
        if (files == null)
            return;
        for (File file : files) {
            if (file.isDirectory()) {
                doScannerWebServlet(packageName + "." + file.getName());
            } else {
                String className = packageName + "." + file.getName().replace(".class", "");
                Class<?> clazz = Class.forName(className);
                WebServlet webServlet = clazz.getAnnotation(WebServlet.class);
                if (webServlet == null)
                    continue;

                // 加载Servlet
                ServletMapping servletMapping = new ServletMapping();
                servletMapping.setServletName(webServlet.name());
                servletMapping.setUrlPattern(webServlet.urlPattern());
                servletMapping.setClassName(clazz.getTypeName());
                urlServletMap.put(webServlet.urlPattern(), servletMapping);

                // 实例化Servlet
                // if(webServlet.loadOnStart() >= 1) // 直接实例化所有Servlet
                MyHttpServlet servlet = (MyHttpServlet) clazz.getDeclaredConstructor().newInstance();
                initServlet(servlet);
                servletMap.put(webServlet.urlPattern(), servlet); // 将Servlet对象装入
            }
        }
    }

    // 调用相关servlet
    private void dispatch(MyHttpServletRequest request, MyHttpServletResponse response) {
        String servletPath = request.getServletPath();
        if (servletPath == null)
            servletPath = "/404";
        try {
            MyHttpServlet servlet = servletMap.get(servletPath);
            if (servlet == null) { // 还没有被初始化
                servlet = servletMap.get("/*");
                if (servlet == null) { // 找不到对应的Servlet
                    new _404Servlet().service(request, response);
                    return;
                }
            }
            servlet.service(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化Servlet
     */
    private void initServlet(MyHttpServlet servlet) throws Exception {
        ServletConfig servletConfig = new ServletConfig() {
            private WebServlet webServlet = servlet.getClass().getAnnotation(WebServlet.class); // not null

            @Override
            public String getServletName() {
                return webServlet.name();
            }

            @Override
            public String getInitParameter(String name) {
                WebInitParam[] webInitParams = webServlet.initParams();
                String value = null;
                for (WebInitParam webInitParam : webInitParams) {
                    if (name.equals(webInitParam.name()))
                        value = webInitParam.value();
                }
                return value;
            }
        };
        servlet.init(servletConfig);
    }


}
